In [1]:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from pylab import imread
%matplotlib inline
from mpl_toolkits.mplot3d import Axes3D
On place un long multiprise dans le champ de la caméra, de sorte que les extrémités du multiprise coïncident avec les bords gauche et droit de l'image captée par la caméra.
On place une tige verticale sur le côté de la caméra, et une lumière vive derrière la tige, afin de projeter l'ombre de la tige sur le milieu du multiprises, matérialisé sur les photos par une bouteille de Club Mate.
On mesure différentes distances parmis les objets ainsi placés:
On prend plusieurs photos de la scène ainsi formée en y plaçant un objet (une boîte en carton) à différents endroits. Lors de chaque photo, on note la distance entre l'avant de l'objet et l'avant du multiprises. Cette distance, en cm, donne le nom de l'image (exemple: 21cm devant le multiprises = 21.jpg, 11.5cm = 11-5.jpg).
Sur les images ainsi obtenues, nous marquons d'une ligne rouge l'ombre sur la boîte. Un programme doit trianguler la position de l'objet, et la position ainsi obtenue doit correspondre (dans les limites de précision peu élevées correspondant aux mesures prises) à la position mesurée (le nom de l'image).
In [11]:
name = "21"
img = imread(name + ".bmp")
img_red = imread(name + "+red.bmp")
In [12]:
diff = img_red - img
plt.imshow(img_red)
plt.show()
plt.imshow(diff)
Out[12]:
Nous savons que le point est à l'intersection du laser et du rayon sortant de la caméra, donc
$ A + \lambda (B - A) - \mu P' = 0 $
$ \begin{pmatrix} i \\ j \end{pmatrix} + \lambda \begin{pmatrix} -i \\ k-j \end{pmatrix} - \mu \begin{pmatrix} k\tan(\theta) \\ k \end{pmatrix} \Leftrightarrow \begin{pmatrix} i & k \tan(\theta) \\ j-k & k \end{pmatrix} \begin{pmatrix} \lambda \\ \mu \end{pmatrix} = \begin{pmatrix} i \\ j \end{pmatrix} $
In [13]:
from math import tan
k = 58.0 # Distance de la camera au point ou le laser est au centre de l'image (cm)
i, j = -45.0, 26.5 #Position du laser par rapport à la camera
A, B = np.array([i,j]), np.array([0,k])
Ax, Ay = A
Bx, By = B
# (x,y)
def pos(theta):
matrix = np.array([[Ax, By*tan(theta)], [Ay-By, By]])
l, m = np.linalg.solve(matrix, A)
return A + l*(B-A)
φ
l'angle maximal entre le centre et le bord (droit) de l'imageE
la largeur de l'image en pixels, e
la distance en pixels entre le centre de l'image et l'image de p
m
la largeur réelle entre les 2 bords observables en b
m = 2*k*tan(φ) => φ = atan(m/2k)
θ = φ * e/(E/2)
In [14]:
from math import atan, pi
m = 69
phi = atan(float(m)/(2*k))
E = diff.shape[1]
print "Ouverture camera:", 180*phi/pi, "degrés. Points détectés:"
theta = lambda e: phi * e/(E/2)
X, Y = [], []
XY = []
i = 260
j_save = 0
for j in range(diff.shape[1]):
if tuple(diff[i][j]) != (0, 0, 0):
j_save = j
t = theta(j - E/2)
XY.append(pos(t))
print XY[-1]
X, Y = map(np.array, zip(*XY))
In [17]:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d', aspect="equal")
ax.scatter(X, Y, [0 for i in range(len(X))])
Out[17]:
In [18]:
#shortcut for vector
vec = lambda *args : np.array(args)
fig = plt.subplot(111, aspect='equal')
# Computed points from above
fig.scatter(X, Y)
def line(direction, position=np.array([0, 0]), **kwargs):
"""Draw a parametric line"""
xy = [position + t*direction for t in np.linspace(0, 1)]
x, y = zip(*xy)
fig.plot(x, y, **kwargs)
# Image background
line(vec(m, 0), position=vec(-m/2, k), color='black', linewidth=3)
# A ray from the camera
line(pos(theta(j_save - E/2)), color='y')
# Camera left limit
line(vec(tan(theta(-E/2))*k, k), color='g')
# Camera right limit
line(vec(tan(theta(E/2))*k, k), color='g')
#Laser ray
line(B-A, A, color='r')
#System parameters
line(B, color='m', ls='--')
line(A*vec(1, 0), color='m', ls='--')
line(A*vec(0, 1), A*vec(1, 0), color='m', ls='--')
fig.set_aspect('equal')
plt.show()
plt.imshow(img_red)
Out[18]:
In [210]:
from math import pi
XY = [pos(t) for t in np.linspace(-phi, phi)]
X, Y = map(np.array, zip(*XY))
plt.xlim(-m/2, m/2)
plt.ylim(0, 2*k)
plt.scatter(X, Y)
Out[210]:
In [110]:
In [ ]: